package service

import (
	"gitee.com/zaiqiang231/lovesport-user-service/app/model"
	"gitee.com/zaiqiang231/lovesport-user-service/app/store"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"strconv"
)

type ServiceMenu struct{}

var ServiceMenuInstance = new(ServiceMenu)

func (menuService *ServiceMenu) GetMenuTree(authorityId uint) (menus []model.SysMenu, err error) {
	menuTree, err := menuService.getMenuTreeMap(authorityId)
	menus = menuTree["0"]
	for i := 0; i < len(menus); i++ {
		err = menuService.getChildrenList(&menus[i], menuTree)
	}
	return menus, err
}

func (menuService *ServiceMenu) getMenuTreeMap(authorityId uint) (treeMap map[string][]model.SysMenu, err error) {
	var allMenus []model.SysMenu
	var baseMenu []model.SysBaseMenu
	treeMap = make(map[string][]model.SysMenu)

	var SysAuthorityMenus []model.SysAuthorityMenu
	err = store.GetDataStore().DB.Where("sys_authority_authority_id = ?", authorityId).Find(&SysAuthorityMenus).Error
	if err != nil {
		return
	}

	var MenuIds []string

	for i := range SysAuthorityMenus {
		MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId)
	}

	err = store.GetDataStore().DB.Where("id in (?)", MenuIds).Order("sort").Preload("Parameters").Find(&baseMenu).Error
	if err != nil {
		return
	}

	for i := range baseMenu {
		allMenus = append(allMenus, model.SysMenu{
			SysBaseMenu: baseMenu[i],
			AuthorityId: authorityId,
			MenuId:      strconv.Itoa(int(baseMenu[i].ID)),
			Parameters:  baseMenu[i].Parameters,
		})
	}

	for _, v := range allMenus {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	return treeMap, err
}

func (menuService *ServiceMenu) getChildrenList(menu *model.SysMenu, treeMap map[string][]model.SysMenu) (err error) {
	menu.Children = treeMap[menu.MenuId]
	for i := 0; i < len(menu.Children); i++ {
		err = menuService.getChildrenList(&menu.Children[i], treeMap)
	}
	return err
}

func (menuService *ServiceMenu) GetMenuAuthority(authorityId uint) (menus []model.SysMenu, err error) {
	var baseMenu []model.SysBaseMenu
	var SysAuthorityMenus []model.SysAuthorityMenu
	err = store.GetDataStore().DB.Where("sys_authority_authority_id = ?", authorityId).Find(&SysAuthorityMenus).Error
	if err != nil {
		return
	}

	var MenuIds []string

	for i := range SysAuthorityMenus {
		MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId)
	}

	err = store.GetDataStore().DB.Where("id in (?) ", MenuIds).Order("sort").Find(&baseMenu).Error

	for i := range baseMenu {
		menus = append(menus, model.SysMenu{
			SysBaseMenu: baseMenu[i],
			AuthorityId: authorityId,
			MenuId:      strconv.Itoa(int(baseMenu[i].ID)),
			Parameters:  baseMenu[i].Parameters,
		})
	}
	return menus, err
}

func (menuService *ServiceMenu) GetInfoList() (list interface{}, total int64, err error) {
	var menuList []model.SysBaseMenu
	treeMap, err := menuService.getBaseMenuTreeMap()
	menuList = treeMap["0"]
	for i := 0; i < len(menuList); i++ {
		err = menuService.getBaseChildrenList(&menuList[i], treeMap)
	}
	return menuList, total, err
}

// 获取基础路由树
func (menuService *ServiceMenu) getBaseMenuTreeMap() (treeMap map[string][]model.SysBaseMenu, err error) {
	var allMenus []model.SysBaseMenu
	treeMap = make(map[string][]model.SysBaseMenu)
	store.GetDataStore().Menu().Execute(func(db *gorm.DB) {
		err = db.Order("sort").Preload("Parameters").Find(&allMenus).Error
	})
	for _, v := range allMenus {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	return treeMap, err
}

// 获取菜单的子菜单
func (menuService *ServiceMenu) getBaseChildrenList(menu *model.SysBaseMenu, treeMap map[string][]model.SysBaseMenu) (err error) {
	menu.Children = treeMap[strconv.Itoa(int(menu.ID))]
	for i := 0; i < len(menu.Children); i++ {
		err = menuService.getBaseChildrenList(&menu.Children[i], treeMap)
	}
	return err
}

func (menuService *ServiceMenu) GetBaseMenuById(id uint) (menu model.SysBaseMenu, err error) {
	store.GetDataStore().Menu().Execute(func(db *gorm.DB) {
		err = db.Preload("Parameters").Where("id = ?", id).First(&menu).Error
	})
	return
}

func (menuService *ServiceMenu) AddBaseMenu(menu model.SysBaseMenu) (err error) {
	store.GetDataStore().Menu().Execute(func(db *gorm.DB) {
		if !errors.Is(db.Where("name = ?", menu.Name).First(&model.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
			err = errors.New("存在重复name，请修改name")
			return
		}
		err = db.Create(&menu).Error
	})
	return
}

func (menuService *ServiceMenu) DeleteBaseMenu(id uint) (err error) {
	store.GetDataStore().Menu().Execute(func(db *gorm.DB) {
		db.Transaction(func(tx *gorm.DB) error {
			if !errors.Is(tx.Preload("Parameters").Where("parent_id = ?", id).First(&model.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
				err = errors.New("此菜单存在子菜单不可删除")
			} else {
				var menu model.SysBaseMenu
				err = tx.Preload("SysAuthorities").Where("id = ?", id).First(&menu).Delete(&menu).Error
				if err != nil {
					return err
				}
				err = tx.Delete(&model.SysBaseMenuParameter{}, "sys_base_menu_id = ?", id).Error
				if err != nil {
					return err
				}
				if len(menu.SysAuthorities) > 0 {
					err = tx.Model(&menu).Association("SysAuthorities").Delete(&menu.SysAuthorities)
				}
			}
			return err
		})
	})
	return err
}

func (menuService *ServiceMenu) UpdateBaseMenu(menu model.SysBaseMenu) (err error) {
	store.GetDataStore().Menu().Execute(func(db *gorm.DB) {
		err = db.Transaction(func(tx *gorm.DB) error {
			var oldMenu model.SysBaseMenu
			if errors.Is(tx.Where("id = ?", menu.ID).First(&oldMenu).Error, gorm.ErrRecordNotFound) {
				return errors.New("原菜单不存在")
			} else {
				if !errors.Is(tx.Where("id <> ? AND name = ?", menu.ID, menu.Name).First(&model.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) {
					return errors.New("存在相同name修改失败")
				}
			}

			txErr := tx.Unscoped().Delete(&model.SysBaseMenuParameter{}, "sys_base_menu_id = ?", menu.ID).Error
			if txErr != nil {
				return txErr
			}
			txErr = tx.Model(&oldMenu).Updates(&menu).Error
			if txErr != nil {
				return txErr
			}
			txErr = tx.Model(&oldMenu).Association("Parameters").Replace(menu.Parameters)
			return txErr
		})
	})
	return err
}
